import processing.core.*; import processing.serial.*; import oscP5.*; import netP5.*; import java.applet.*; import java.awt.*; import java.awt.image.*; import java.awt.event.*; import java.io.*; import java.net.*; import java.text.*; import java.util.*; import java.util.zip.*; public class capture2tile2arduino extends PApplet {





PFont _myHelvetica;
PFont _myEidetic;


boolean _myIsPaused = false;

PrinterThread _myPrinterThread;
PImage targetImage;
PImage equalizeImage;
PImage ditherImage;
PImage captureImage;

OscP5 oscP5;
public void setup(){
  size(600,500);
  oscP5 = new OscP5(this,7000);
  oscP5.plug(this,"capture","/capture");


  _myHelvetica = loadFont("HelveticaNeue-Bold-24.vlw");

  _myEidetic = loadFont("EideticNeo-Italic-18.vlw");
  targetImage = new PImage(160,160);
  ditherImage = new PImage(160,160);
  equalizeImage = new PImage(160,160);



  Serial thePort = new Serial(this, Serial.list()[0], 19200);
  println(Serial.list());

  _myPrinterThread = new PrinterThread(thePort, ditherImage); 

}




public void capture(int theX, int theY, int theRadius, String theFile) {
  println("### plug event method. received a message /capture.");
  println("received: "+theX+", "+theY+", "+theRadius+", "+theFile); 



  if(!_myPrinterThread.isBusy() && !_myIsPaused) {
    captureImage = loadImage(theFile); 
    targetImage.copy(captureImage, theX-theRadius, theY-theRadius, theRadius*2, theRadius*2, 0, 0, 160, 160);
    equalizeImage();
    ditherImage();
    _myPrinterThread.startPrint();

  }

}

public void draw(){
  background(50,40,30);
  fill(255);
  noStroke();
  textFont(_myHelvetica);
  text("ICSY TK 5000",40,40);
  textFont(_myEidetic);
  text("mission control 0.1 alpha", 220, 40);
  text("last image",40,90);

  if(targetImage != null) image(targetImage, 40, 100);
  if(equalizeImage != null) image(equalizeImage, 220, 100);
  if(ditherImage != null) image(ditherImage, 400, 100);
  text("progress",40,290);

  rect(40,300,_myPrinterThread.getProgress() * (width-80), 20);

  text("status",40,350);
  textFont(_myHelvetica);
  if(_myIsPaused){
  text("PAUSED",40,370);
  }



}

public void equalizeImage(){
  targetImage.loadPixels();
   equalizeImage.loadPixels();
   int cmin = 255;
   int cmax = 0;
  
  for (int x=0;x<targetImage.width;x++) {
    for (int y=0;y<targetImage.height;y++) {
      int c = (int)red(targetImage.get(x,y));
      cmin = min(cmin, c);
            cmax = max(cmax, c);
    }
    
  }
  
    for (int x=0;x<targetImage.width;x++) {
    for (int y=0;y<targetImage.height;y++) {
      int c =  (int)map(red(targetImage.get(x,y)), cmin, cmax, 0, 255);
      equalizeImage.set(x,y,color(c));
    }
    
  }
  equalizeImage.updatePixels();
  

}

public void ditherImage(){
  ditherImage.loadPixels();
  
  int n = 4;
  float f=255.f/(pow(2,2*n)+1);
  for (int x=0;x<equalizeImage.width;x++) {
    for (int y=0;y<equalizeImage.height;y++) {
      int c=equalizeImage.get(x,y);
      float t=(n>0?dizza(x,y,n)*f:128);
      if (n==5) {        
      } 
      else {
        c=color(t>=(red(c)+green(c)+blue(c))/3.f?0:255);
      }
      ditherImage.set(x,y,c);
    }
  }
  
    ditherImage.updatePixels();

}




public void keyPressed(){
  if(key == 'p') _myIsPaused = !_myIsPaused;
}

public int dizza(int i, int j, int n) {
  if (n==1) {
    return (i%2!=j%2 ? 2 : 0) + j%2;
  }
  else{
    return 4*dizza(i%2, j%2, n-1) + dizza(PApplet.parseInt(i/2), PApplet.parseInt(j/2), n-1);
  }
}


public class PrinterThread implements Runnable{
  private Thread _myRunner;

  private float _myProgress = 0;
  private boolean _myIsPrinting = false;
  private boolean _myShouldPrint = false;

  private Serial _myPort;
  private PImage _myImage;

  private int COLS = 20;
  private int ROWS = 2;
  private int LINES = 0;

  private int[][] _myLines; 

  public PrinterThread(Serial thePort, PImage theImage){

    _myPort = thePort;
    _myImage = theImage;
    _myRunner = new Thread(this); 

    _myRunner.start();

  }

  public void run(){

    while(true){
      if(_myShouldPrint){

        _myIsPrinting = true;
        processImage();
        sendImage();

        _myShouldPrint = false;
      }
      else {
        try{ 
          Thread.sleep(1000); 
        } 
        catch(Exception ex){ 
        };
      }


    }


  }



  public void sendImage(){


    println("### Starting print ");

    for(int l = 0; l < LINES; l++){
      for(int i = 0; i< 640; i++){

        _myPort.write(_myLines[l][i]); 
      } 

      _myProgress = (l+1)/(float)LINES;


      try{
        Thread.sleep(1800);  // TODO: Actually wait for printer
      } 
      catch(Exception ex){ 
        println(ex);
      }

    }
    try{
      Thread.sleep(1800);
    } 
    catch(Exception ex){ 
    }
    println("### Finished printing");
    _myProgress = 0;
    _myIsPrinting = false;



  }

  public void processImage(){

    println("### Processing image ");

    LINES = _myImage.height / 16;

    _myLines = new int[LINES][640];

    for(int l = 0; l < LINES; l++){

      int arrayIndex = 0;

      int length = COLS * ROWS * LINES;


      for(int r = 0; r<ROWS; r++){
        for(int c = 0; c<COLS; c++){

          for(int ir=0; ir<8; ir++){
            int bp1 = 0;
            int bp2 = 0;


            for(int ic=0; ic<8; ic++){
              int p = _myImage.get(c*8+ic, r*8+ir+l*16);
              if(red(p) <128) {
                bp1 += 1 << (7-ic);
              }
              bp2 = bp1;
            } 





            _myLines[l][arrayIndex ] = (int)bp1;

            arrayIndex++;
            _myLines[l][arrayIndex ] = (int)bp2;
            arrayIndex++;


          }
        } 
      }

    }


  }

  public void startPrint(){
    _myShouldPrint = true;
  }

  public float getProgress(){
    return  _myProgress; 
  }

  public boolean isBusy(){
    return _myIsPrinting;
  }

}

  static public void main(String args[]) {     PApplet.main(new String[] { "capture2tile2arduino" });  }}